/******************************************************************************
 * FileName:    gwin_utc_clock.c
 * Desc:        世界时间
 *
 *
 * Author:      Lin
 * Notes:
 *
 ******************************************************************************/

/*-------------------------- Includes ---------------------------------------*/
#include "gwin_utc_clock.h"


/*-------------------------- Macro Definitions ------------------------------*/

/*-------------------------- Type Declarations ------------------------------*/

/*-------------------------- Global Variables -------------------------------*/

/*-------------------------- Local Variables --------------------------------*/

/*-------------------------- Functions Declarations -------------------------*/

/*-------------------------- Functions Definitions --------------------------*/
/**
 * @brief 判断是否是闰年
 */
static uint8_t gwin_utc_clock_check_is_leap_year(uint16_t year)
{
    return (!((year) % 400) || (((year) % 100) && !((year) % 4)));
}

/**
 * @brief 获取每年天数
 */
static uint16_t gwin_utc_clock_get_day_from_year(uint16_t year)
{
    return gwin_utc_clock_check_is_leap_year(year) ? 366 : 365;
}

/**
 * @brief 获取每月天数
 */
static uint8_t gwin_utc_clock_get_day_from_month(uint8_t is_leap_year, uint8_t month)
{
    uint8_t day = 30;

    if (month == 2)         // 二月
    {
        day = (28 + is_leap_year);
    }
    else                    // 其他月份
    {
        // 1 3 5 7 8 10 12 有31日
        // 小于8月，单数月份有31日；大于等于8月，双数月份有31日
        if (month >= 8)
        {
            month--;
        }

        if (month % 2)
        {
            day = 31;
        }
    }

    return day;
}

/**
 * @brief 根据日期判断出星期几(0-6)0为星期一，6为星期日
 */
static uint8_t get_week_from_date(uint16_t year, uint8_t month, uint8_t day)
{
    if (month == 1 || month == 2)
    {
        month += 12;
        year--;
    }

    int c = year / 100;
    int y = year % 100;
    int m = month;
    int d = day;
    int week = c / 4 - 2 * c + y + y / 4 + 13 * (m + 1) / 5 + d - 1;
    if (week < 0)
    {
        week = (week + (-week / 7 + 1) * 7) % 7;
    }
    else
    {
        week = week % 7;
    }
    week -= 1;
    if (week < 0)
    {
        week = 6;
    }

    return week;
}

/**
 * @brief 时间戳 转换 年月日时分秒
 *          时间戳开始时间：1970-01-01 00:00:00
 *          北京开始时间：    1970-01-01 08:00:00
 */
void gwin_utc_clock_timestamp_to_datetime(const uint32_t *timestamp, gwin_utc_clock_datetime_t *datetime)
{
    if (timestamp == NULL || datetime == NULL)
    {
        return;
    }

    uint32_t ts = *timestamp;
    gwin_utc_clock_datetime_t dt = { 0x00 };
    uint32_t total_day = 0;
    uint32_t remain_second = 0;

    // 赋予开始时间
    dt.year = 1970;
    dt.month = 1;
    dt.day = 1;
    #if DEFAULT_BEIJING_TIME
    timestamp += 8 * 60 * 60;
    #endif

    // 超过一天的秒数，得出总天数
    total_day = ts / ONE_DAY_SECOND;
    // 计算年
    while (total_day >= gwin_utc_clock_get_day_from_year(dt.year))
    {
        total_day -= gwin_utc_clock_get_day_from_year(dt.year);
        dt.year++;
    }
    // 计算月
    while (total_day >= gwin_utc_clock_get_day_from_month(gwin_utc_clock_check_is_leap_year(dt.year), dt.month))
    {
        total_day -= gwin_utc_clock_get_day_from_month(gwin_utc_clock_check_is_leap_year(dt.year), dt.month);
        dt.month++;
    }
    // 计算日
    dt.day += total_day;

    // 不足一天的秒数
    remain_second = ts % ONE_DAY_SECOND;
    // 计算时
    dt.hour = remain_second / 3600;
    // 计算分
    dt.minute = remain_second % 3600 / 60;
    // 计算秒
    dt.second = remain_second % 60;

    // 计算星期
    dt.week = get_week_from_date(dt.year, dt.month, dt.day);

    memcpy(datetime, &dt, sizeof(gwin_utc_clock_datetime_t));
}

/**
 * @brief 年月日时分秒 转换 时间戳
 *          时间戳开始时间：1970-01-01 00:00:00
 *          北京开始时间：    1970-01-01 08:00:00
 */
void gwin_utc_clock_datetime_to_timestamp(uint32_t *timestamp, const gwin_utc_clock_datetime_t *datetime)
{
    if (timestamp == NULL || datetime == NULL)
    {
        return;
    }

    uint32_t ts = 0;
    gwin_utc_clock_datetime_t dt = *datetime;

    if (dt.year >= 1970 && dt.month >= 1 && dt.day >= 1)
    {
        // 时分秒计算秒数
        ts = dt.hour * 60 * 60 + dt.minute * 60 + dt.second;

        // 加上日秒数
        ts += ONE_DAY_SECOND * (dt.day - 1);

        // 加上月秒数
        for (uint8_t i = 1; i < dt.month; i++)
        {
            ts += gwin_utc_clock_get_day_from_month(gwin_utc_clock_check_is_leap_year(dt.year), i) * ONE_DAY_SECOND;
        }

        // 加上年秒数
        for (uint16_t i = 1970; i < dt.year; i++)
        {
            if (gwin_utc_clock_check_is_leap_year(i))
            {
                ts += 366 * ONE_DAY_SECOND;
            }
            else
            {
                ts += 365 * ONE_DAY_SECOND;
            }
        }

        #if DEFAULT_BEIJING_TIME
        if (ts > 8 * 60 * 60)
        {
            ts -= 8 * 60 * 60;
        }else
        {
            ts = 0;
        }
        #endif
    }

    *timestamp = ts;
}

/*-------------------------- END OF FILE ------------------------------------*/

